
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import { isFunction, isObject, retrieve2 } from 'zrender/lib/core/util.js';
import { makeInner } from '../util/model.js'; // Stored properties for further transition.

export var transitionStore = makeInner();
/**
 * Return null if animation is disabled.
 */

export function getAnimationConfig(animationType, animatableModel, dataIndex, // Extra opts can override the option in animatable model.
	extraOpts, // TODO It's only for pictorial bar now.
	extraDelayParams) {
	var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option.
	// If animation is enabled. Will use this animation config in payload.
	// If animation is disabled. Just ignore it.

	if (animatableModel && animatableModel.ecModel) {
		var updatePayload = animatableModel.ecModel.getUpdatePayload();
		animationPayload = updatePayload && updatePayload.animation;
	}

	var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();
	var isUpdate = animationType === 'update';

	if (animationEnabled) {
		var duration = void 0;
		var easing = void 0;
		var delay = void 0;

		if (extraOpts) {
			duration = retrieve2(extraOpts.duration, 200);
			easing = retrieve2(extraOpts.easing, 'cubicOut');
			delay = 0;
		} else {
			duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration');
			easing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing');
			delay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay');
		} // animation from payload has highest priority.

		if (animationPayload) {
			animationPayload.duration != null && (duration = animationPayload.duration);
			animationPayload.easing != null && (easing = animationPayload.easing);
			animationPayload.delay != null && (delay = animationPayload.delay);
		}

		if (isFunction(delay)) {
			delay = delay(dataIndex, extraDelayParams);
		}

		if (isFunction(duration)) {
			duration = duration(dataIndex);
		}

		var config = {
			duration: duration || 0,
			delay: delay,
			easing: easing
		};
		return config;
	} else {
		return null;
	}
}

function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) {
	var isFrom = false;
	var removeOpt;

	if (isFunction(dataIndex)) {
		during = cb;
		cb = dataIndex;
		dataIndex = null;
	} else if (isObject(dataIndex)) {
		cb = dataIndex.cb;
		during = dataIndex.during;
		isFrom = dataIndex.isFrom;
		removeOpt = dataIndex.removeOpt;
		dataIndex = dataIndex.dataIndex;
	}

	var isRemove = animationType === 'leave';

	if (!isRemove) {
		// Must stop the remove animation.
		el.stopAnimation('leave');
	}

	var animationConfig = getAnimationConfig(animationType, animatableModel, dataIndex, isRemove ? removeOpt || {} : null, animatableModel && animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null);

	if (animationConfig && animationConfig.duration > 0) {
		var duration = animationConfig.duration;
		var animationDelay = animationConfig.delay;
		var animationEasing = animationConfig.easing;
		var animateConfig = {
			duration: duration,
			delay: animationDelay || 0,
			easing: animationEasing,
			done: cb,
			force: !!cb || !!during,
			// Set to final state in update/init animation.
			// So the post processing based on the path shape can be done correctly.
			setToFinal: !isRemove,
			scope: animationType,
			during: during
		};
		isFrom ? el.animateFrom(props, animateConfig) : el.animateTo(props, animateConfig);
	} else {
		el.stopAnimation(); // If `isFrom`, the props is the "from" props.

		!isFrom && el.attr(props); // Call during at least once.

		during && during(1);
		cb && cb();
	}
}
/**
 * Update graphic element properties with or without animation according to the
 * configuration in series.
 *
 * Caution: this method will stop previous animation.
 * So do not use this method to one element twice before
 * animation starts, unless you know what you are doing.
 * @example
 *     graphic.updateProps(el, {
 *         position: [100, 100]
 *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });
 *     // Or
 *     graphic.updateProps(el, {
 *         position: [100, 100]
 *     }, seriesModel, function () { console.log('Animation done!'); });
 */

function updateProps(el, props, // TODO: TYPE AnimatableModel
	animatableModel, dataIndex, cb, during) {
	animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during);
}

export { updateProps };
/**
 * Init graphic element properties with or without animation according to the
 * configuration in series.
 *
 * Caution: this method will stop previous animation.
 * So do not use this method to one element twice before
 * animation starts, unless you know what you are doing.
 */

export function initProps(el, props, animatableModel, dataIndex, cb, during) {
	animateOrSetProps('enter', el, props, animatableModel, dataIndex, cb, during);
}
/**
 * If element is removed.
 * It can determine if element is having remove animation.
 */

export function isElementRemoved(el) {
	if (!el.__zr) {
		return true;
	}

	for (var i = 0; i < el.animators.length; i++) {
		var animator = el.animators[i];

		if (animator.scope === 'leave') {
			return true;
		}
	}

	return false;
}
/**
 * Remove graphic element
 */

export function removeElement(el, props, animatableModel, dataIndex, cb, during) {
	// Don't do remove animation twice.
	if (isElementRemoved(el)) {
		return;
	}

	animateOrSetProps('leave', el, props, animatableModel, dataIndex, cb, during);
}

function fadeOutDisplayable(el, animatableModel, dataIndex, done) {
	el.removeTextContent();
	el.removeTextGuideLine();
	removeElement(el, {
		style: {
			opacity: 0
		}
	}, animatableModel, dataIndex, done);
}

export function removeElementWithFadeOut(el, animatableModel, dataIndex) {
	function doRemove() {
		el.parent && el.parent.remove(el);
	} // Hide label and labelLine first
	// TODO Also use fade out animation?

	if (!el.isGroup) {
		fadeOutDisplayable(el, animatableModel, dataIndex, doRemove);
	} else {
		el.traverse(function (disp) {
			if (!disp.isGroup) {
				// Can invoke doRemove multiple times.
				fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove);
			}
		});
	}
}
/**
 * Save old style for style transition in universalTransition module.
 * It's used when element will be reused in each render.
 * For chart like map, heatmap, which will always create new element.
 * We don't need to save this because universalTransition can get old style from the old element
 */

export function saveOldStyle(el) {
	transitionStore(el).oldStyle = el.style;
}
export function getOldStyle(el) {
	return transitionStore(el).oldStyle;
}